home *** CD-ROM | disk | FTP | other *** search
/ SGI Freeware 1999 August / SGI Freeware 1999 August.iso / dist / fw_emacs.idb / usr / freeware / share / emacs / 19.34 / lisp / cust-print.el.z / cust-print.el
Encoding:
Text File  |  1998-10-28  |  25.8 KB  |  746 lines

  1. ;;; cust-print.el --- handles print-level and print-circle.
  2.  
  3. ;; Copyright (C) 1992 Free Software Foundation, Inc.
  4.  
  5. ;; Author: Daniel LaLiberte <liberte@cs.uiuc.edu>
  6. ;; Adapted-By: ESR
  7. ;; Keywords: extensions
  8.  
  9. ;; LCD Archive Entry:
  10. ;; cust-print|Daniel LaLiberte|liberte@cs.uiuc.edu
  11. ;; |Handle print-level, print-circle and more.
  12. ;; |$Date: 1996/01/14 07:34:30 $|$Revision: 2.1.1.4 $|
  13.  
  14. ;; This file is part of GNU Emacs.
  15.  
  16. ;; GNU Emacs is free software; you can redistribute it and/or modify
  17. ;; it under the terms of the GNU General Public License as published by
  18. ;; the Free Software Foundation; either version 2, or (at your option)
  19. ;; any later version.
  20.  
  21. ;; GNU Emacs is distributed in the hope that it will be useful,
  22. ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
  23. ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  24. ;; GNU General Public License for more details.
  25.  
  26. ;; You should have received a copy of the GNU General Public License
  27. ;; along with GNU Emacs; see the file COPYING.  If not, write to the
  28. ;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
  29. ;; Boston, MA 02111-1307, USA.
  30.  
  31. ;; ===============================
  32. ;; $Header: /home/gd/gnu/emacs/19.0/lisp/RCS/cust-print.el,v 2.1.1.4 1996/01/14 07:34:30 erik Exp $
  33. ;; $Log: cust-print.el,v $
  34. ;; Revision 2.1.1.4  1996/01/14 07:34:30  erik
  35. ;; Update FSF's address.
  36. ;;
  37. ;; Revision 2.1.1.3  1996/01/05 00:08:36  kwzh
  38. ;; Comment fixes.
  39. ;;
  40. ;; Revision 2.1.1.2  1995/03/16 04:36:01  rms
  41. ;; Comment change.
  42. ;;
  43. ;; Revision 2.1.1.1  1994/04/09  22:24:43  liberte
  44. ;; Branch for FSF mods.
  45. ;;
  46. ;; Revision 2.1  1994/04/09  22:19:10  liberte
  47. ;; Jumping up to new revision.
  48. ;; Simplify definition of defalias for Emacs 18.
  49. ;;
  50. ;; Revision 2.1  1994/04/09  22:19:10  liberte
  51. ;; Jumping up to new revision.
  52. ;; Simplify definition of defalias for Emacs 18.
  53. ;;
  54. ;; Revision 1.14  1994/04/05  21:05:09  liberte
  55. ;; Change install- and uninstall- to -install and -uninstall.
  56. ;;
  57. ;; Revision 1.13  1994/03/24  20:26:05  liberte
  58. ;; Change "internal" to "original" throughout.
  59. ;;         (add-custom-printer, delete-custom-printer) replace customizers.
  60. ;;         (with-custom-print) new
  61. ;;         (custom-prin1-to-string) Made it more robust.
  62. ;;
  63. ;; Revision 1.4  1994/03/23  20:34:29  liberte
  64. ;; * Change "emacs" to "original" - I just can't decide. 
  65. ;;
  66. ;; Revision 1.3  1994/02/21  21:25:36  liberte
  67. ;; * Make custom-prin1-to-string more robust when errors occur.
  68. ;; * Change "internal" to "emacs".
  69. ;;
  70. ;; Revision 1.2  1993/11/22  22:36:36  liberte
  71. ;; * Simplified and generalized printer customization.
  72. ;;     custom-printers is an alist of (PREDICATE . PRINTER) pairs
  73. ;;     for any data types.  The PRINTER function should print to
  74. ;;     `standard-output'  add-custom-printer and delete-custom-printer
  75. ;;     change custom-printers.
  76. ;;
  77. ;; * Installation function now called install-custom-print.  The
  78. ;;     old name is still around for now.
  79. ;;
  80. ;; * New macro with-custom-print (added earlier) - executes like
  81. ;;     progn but with custom-print activated temporarily.
  82. ;;
  83. ;; * Cleaned up comments for replacements of standard printers.
  84. ;;
  85. ;; * Changed custom-prin1-to-string to use a temporary buffer.
  86. ;;
  87. ;; * Option custom-print-vectors (added earlier) - controls whether
  88. ;;     vectors should be printed according to print-length and
  89. ;;     print-length.  Emacs doesn't do this, but cust-print would
  90. ;;     otherwise do it only if custom printing is required.
  91. ;;
  92. ;; * Uninterned symbols are treated as non-read-equivalent.
  93. ;;
  94.  
  95.  
  96. ;;; Commentary:
  97.  
  98. ;; This package provides a general print handler for prin1 and princ
  99. ;; that supports print-level and print-circle, and by the way,
  100. ;; print-length since the standard routines are being replaced.  Also,
  101. ;; to print custom types constructed from lists and vectors, use
  102. ;; custom-print-list and custom-print-vector.  See the documentation
  103. ;; strings of these variables for more details.  
  104.  
  105. ;; If the results of your expressions contain circular references to
  106. ;; other parts of the same structure, the standard Emacs print
  107. ;; subroutines may fail to print with an untrappable error,
  108. ;; "Apparently circular structure being printed".  If you only use cdr
  109. ;; circular lists (where cdrs of lists point back; what is the right
  110. ;; term here?), you can limit the length of printing with
  111. ;; print-length.  But car circular lists and circular vectors generate
  112. ;; the above mentioned error in Emacs version 18.  Version
  113. ;; 19 supports print-level, but it is often useful to get a better
  114. ;; print representation of circular and shared structures; the print-circle
  115. ;; option may be used to print more concise representations.
  116.  
  117. ;; There are three main ways to use this package.  First, you may
  118. ;; replace prin1, princ, and some subroutines that use them by calling
  119. ;; install-custom-print so that any use of these functions in
  120. ;; Lisp code will be affected; you can later reset with
  121. ;; uninstall-custom-print.  Second, you may temporarily install
  122. ;; these functions with the macro with-custom-print.  Third, you
  123. ;; could call the custom routines directly, thus only affecting the
  124. ;; printing that requires them.
  125.  
  126. ;; Note that subroutines which call print subroutines directly will
  127. ;; not use the custom print functions.  In particular, the evaluation
  128. ;; functions like eval-region call the print subroutines directly.
  129. ;; Therefore, if you evaluate (aref circ-list 0), where circ-list is a
  130. ;; circular list rather than an array, aref calls error directly which
  131. ;; will jump to the top level instead of printing the circular list.
  132.  
  133. ;; Uninterned symbols are recognized when print-circle is non-nil,
  134. ;; but they are not printed specially here.  Use the cl-packages package
  135. ;; to print according to print-gensym.
  136.  
  137. ;; Obviously the right way to implement this custom-print facility is
  138. ;; in C or with hooks into the standard printer.  Please volunteer
  139. ;; since I don't have the time or need.  More CL-like printing
  140. ;; capabilities could be added in the future.
  141.  
  142. ;; Implementation design: we want to use the same list and vector
  143. ;; processing algorithm for all versions of prin1 and princ, since how
  144. ;; the processing is done depends on print-length, print-level, and
  145. ;; print-circle.  For circle printing, a preprocessing step is
  146. ;; required before the final printing.  Thanks to Jamie Zawinski
  147. ;; for motivation and algorithms.
  148.  
  149.  
  150. ;;; Code:
  151.  
  152. ;; If using cl-packages:
  153.  
  154. '(defpackage "cust-print"
  155.    (:nicknames "CP" "custom-print")
  156.    (:use "el")
  157.    (:export
  158.     print-level
  159.     print-circle
  160.  
  161.     custom-print-install
  162.     custom-print-uninstall
  163.     custom-print-installed-p
  164.     with-custom-print
  165.  
  166.     custom-prin1
  167.     custom-princ
  168.     custom-prin1-to-string
  169.     custom-print
  170.     custom-format
  171.     custom-message
  172.     custom-error
  173.  
  174.     custom-printers
  175.     add-custom-printer
  176.     ))
  177.  
  178. '(in-package cust-print)
  179.  
  180. (require 'backquote)
  181.  
  182. ;; Emacs 18 doesn't have defalias.
  183. ;; Provide def for byte compiler.
  184. (eval-and-compile
  185.   (or (fboundp 'defalias) (fset 'defalias 'fset)))
  186.  
  187.  
  188. ;; Variables:
  189. ;;=========================================================
  190.  
  191. ;;(defvar print-length nil
  192. ;;  "*Controls how many elements of a list, at each level, are printed.
  193. ;;This is defined by emacs.")
  194.  
  195. (defvar print-level nil
  196.   "*Controls how many levels deep a nested data object will print.  
  197.  
  198. If nil, printing proceeds recursively and may lead to
  199. max-lisp-eval-depth being exceeded or an error may occur:
  200. `Apparently circular structure being printed.'
  201. Also see `print-length' and `print-circle'.
  202.  
  203. If non-nil, components at levels equal to or greater than `print-level'
  204. are printed simply as `#'.  The object to be printed is at level 0,
  205. and if the object is a list or vector, its top-level components are at
  206. level 1.")
  207.  
  208.  
  209. (defvar print-circle nil
  210.   "*Controls the printing of recursive structures.  
  211.  
  212. If nil, printing proceeds recursively and may lead to
  213. `max-lisp-eval-depth' being exceeded or an error may occur:
  214. \"Apparently circular structure being printed.\"  Also see
  215. `print-length' and `print-level'.
  216.  
  217. If non-nil, shared substructures anywhere in the structure are printed
  218. with `#N=' before the first occurrence (in the order of the print
  219. representation) and `#N#' in place of each subsequent occurrence,
  220. where N is a positive decimal integer.
  221.  
  222. There is no way to read this representation in standard Emacs,
  223. but if you need to do so, try the cl-read.el package.")
  224.  
  225.  
  226. (defvar custom-print-vectors nil
  227.   "*Non-nil if printing of vectors should obey print-level and print-length.
  228.  
  229. For Emacs 18, setting print-level, or adding custom print list or
  230. vector handling will make this happen anyway.  Emacs 19 obeys
  231. print-level, but not for vectors.")
  232.  
  233.  
  234. ;; Custom printers
  235. ;;==========================================================
  236.  
  237. (defconst custom-printers nil
  238.   ;; e.g. '((symbolp . pkg::print-symbol))
  239.   "An alist for custom printing of any type.
  240. Pairs are of the form (PREDICATE . PRINTER).  If PREDICATE is true
  241. for an object, then PRINTER is called with the object.
  242. PRINTER should print to `standard-output' using cust-print-original-princ
  243. if the standard printer is sufficient, or cust-print-prin for complex things.
  244. The PRINTER should return the object being printed.
  245.  
  246. Don't modify this variable directly.  Use `add-custom-printer' and
  247. `delete-custom-printer'")
  248. ;; Should cust-print-original-princ and cust-print-prin be exported symbols?
  249. ;; Or should the standard printers functions be replaced by
  250. ;; CP ones in Emacs Lisp so that CP internal functions need not be called?
  251.  
  252. (defun add-custom-printer (pred printer)
  253.   "Add a pair of PREDICATE and PRINTER to `custom-printers'.
  254. Any pair that has the same PREDICATE is first removed."
  255.   (setq custom-printers (cons (cons pred printer) 
  256.                   (delq (assq pred custom-printers)
  257.                     custom-printers)))
  258.   ;; Rather than updating here, we could wait until cust-print-top-level is called.
  259.   (cust-print-update-custom-printers))
  260.  
  261. (defun delete-custom-printer (pred)
  262.   "Delete the custom printer associated with PREDICATE."
  263.   (setq custom-printers (delq (assq pred custom-printers)
  264.                   custom-printers))
  265.   (cust-print-update-custom-printers))
  266.  
  267.  
  268. (defun cust-print-use-custom-printer (object)
  269.   ;; Default function returns nil.
  270.   nil)
  271.  
  272. (defun cust-print-update-custom-printers ()
  273.   ;; Modify the definition of cust-print-use-custom-printer
  274.   (defalias 'cust-print-use-custom-printer
  275.     ;; We don't really want to require the byte-compiler.
  276.     ;; (byte-compile
  277.      (` (lambda (object)
  278.       (cond
  279.        (,@ (mapcar (function 
  280.             (lambda (pair)
  281.               (` (((, (car pair)) object) 
  282.                   ((, (cdr pair)) object)))))
  283.                custom-printers))
  284.        ;; Otherwise return nil.
  285.        (t nil)
  286.        )))
  287.      ;; )
  288.   ))
  289.  
  290.  
  291. ;; Saving and restoring emacs printing routines.
  292. ;;====================================================
  293.  
  294. (defun cust-print-set-function-cell (symbol-pair)
  295.   (defalias (car symbol-pair) 
  296.     (symbol-function (car (cdr symbol-pair)))))
  297.  
  298. (defun cust-print-original-princ (object &optional stream)) ; dummy def
  299.  
  300. ;; Save emacs routines.
  301. (if (not (fboundp 'cust-print-original-prin1))
  302.     (mapcar 'cust-print-set-function-cell
  303.         '((cust-print-original-prin1 prin1)
  304.           (cust-print-original-princ princ)
  305.           (cust-print-original-print print)
  306.           (cust-print-original-prin1-to-string prin1-to-string)
  307.           (cust-print-original-format format)
  308.           (cust-print-original-message message)
  309.           (cust-print-original-error error))))
  310.  
  311.  
  312. (defun custom-print-install ()
  313.   "Replace print functions with general, customizable, Lisp versions.
  314. The emacs subroutines are saved away, and you can reinstall them
  315. by running `custom-print-uninstall'."
  316.   (interactive)
  317.   (mapcar 'cust-print-set-function-cell
  318.       '((prin1 custom-prin1)
  319.         (princ custom-princ)
  320.         (print custom-print)
  321.         (prin1-to-string custom-prin1-to-string)
  322.         (format custom-format)
  323.         (message custom-message)
  324.         (error custom-error)
  325.         ))
  326.   t)
  327.   
  328. (defun custom-print-uninstall ()
  329.   "Reset print functions to their emacs subroutines."
  330.   (interactive)
  331.   (mapcar 'cust-print-set-function-cell
  332.       '((prin1 cust-print-original-prin1)
  333.         (princ cust-print-original-princ)
  334.         (print cust-print-original-print)
  335.         (prin1-to-string cust-print-original-prin1-to-string)
  336.         (format cust-print-original-format)
  337.         (message cust-print-original-message)
  338.         (error cust-print-original-error)
  339.         ))
  340.   t)
  341.  
  342. (defalias 'custom-print-funcs-installed-p 'custom-print-installed-p)
  343. (defun custom-print-installed-p ()
  344.   "Return t if custom-print is currently installed, nil otherwise."
  345.   (eq (symbol-function 'custom-prin1) (symbol-function 'prin1)))
  346.  
  347. (put 'with-custom-print-funcs 'edebug-form-spec '(body))
  348. (put 'with-custom-print 'edebug-form-spec '(body))
  349.  
  350. (defalias 'with-custom-print-funcs 'with-custom-print)
  351. (defmacro with-custom-print (&rest body)
  352.   "Temporarily install the custom print package while executing BODY."
  353.   (` (unwind-protect
  354.      (progn
  355.        (custom-print-install)
  356.        (,@ body))
  357.        (custom-print-uninstall))))
  358.  
  359.  
  360. ;; Lisp replacements for prin1 and princ, and for some subrs that use them
  361. ;;===============================================================
  362. ;; - so far only the printing and formatting subrs.
  363.  
  364. (defun custom-prin1 (object &optional stream)
  365.   "Output the printed representation of OBJECT, any Lisp object.
  366. Quoting characters are printed when needed to make output that `read'
  367. can handle, whenever this is possible.
  368. Output stream is STREAM, or value of `standard-output' (which see).
  369.  
  370. This is the custom-print replacement for the standard `prin1'.  It
  371. uses the appropriate printer depending on the values of `print-level'
  372. and `print-circle' (which see)."
  373.   (cust-print-top-level object stream 'cust-print-original-prin1))
  374.  
  375.  
  376. (defun custom-princ (object &optional stream)
  377.   "Output the printed representation of OBJECT, any Lisp object.
  378. No quoting characters are used; no delimiters are printed around
  379. the contents of strings.
  380. Output stream is STREAM, or value of `standard-output' (which see).
  381.  
  382. This is the custom-print replacement for the standard `princ'."
  383.   (cust-print-top-level object stream 'cust-print-original-princ))
  384.  
  385.  
  386. (defun custom-prin1-to-string (object)
  387.   "Return a string containing the printed representation of OBJECT,
  388. any Lisp object.  Quoting characters are used when needed to make output
  389. that `read' can handle, whenever this is possible.
  390.  
  391. This is the custom-print replacement for the standard `prin1-to-string'."
  392.   (let ((buf (get-buffer-create " *custom-print-temp*")))
  393.     ;; We must erase the buffer before printing in case an error 
  394.     ;; occurred during the last prin1-to-string and we are in debugger.
  395.     (save-excursion
  396.       (set-buffer buf)
  397.       (erase-buffer))
  398.     ;; We must be in the current-buffer when the print occurs.
  399.     (custom-prin1 object buf)
  400.     (save-excursion
  401.       (set-buffer buf)
  402.       (buffer-string)
  403.       ;; We could erase the buffer again, but why bother?
  404.       )))
  405.  
  406.  
  407. (defun custom-print (object &optional stream)
  408.   "Output the printed representation of OBJECT, with newlines around it.
  409. Quoting characters are printed when needed to make output that `read'
  410. can handle, whenever this is possible.
  411. Output stream is STREAM, or value of `standard-output' (which see).
  412.  
  413. This is the custom-print replacement for the standard `print'."
  414.   (cust-print-original-princ "\n" stream)
  415.   (custom-prin1 object stream)
  416.   (cust-print-original-princ "\n" stream))
  417.  
  418.  
  419. (defun custom-format (fmt &rest args)
  420.   "Format a string out of a control-string and arguments.  
  421. The first argument is a control string.  It, and subsequent arguments
  422. substituted into it, become the value, which is a string.
  423. It may contain %s or %d or %c to substitute successive following arguments.
  424. %s means print an argument as a string, %d means print as number in decimal,
  425. %c means print a number as a single character.
  426. The argument used by %s must be a string or a symbol;
  427. the argument used by %d, %b, %o, %x or %c must be a number.
  428.  
  429. This is the custom-print replacement for the standard `format'.  It
  430. calls the emacs `format' after first making strings for list,
  431. vector, or symbol args.  The format specification for such args should
  432. be `%s' in any case, so a string argument will also work.  The string
  433. is generated with `custom-prin1-to-string', which quotes quotable
  434. characters."
  435.   (apply 'cust-print-original-format fmt
  436.      (mapcar (function (lambda (arg)
  437.                  (if (or (listp arg) (vectorp arg) (symbolp arg))
  438.                  (custom-prin1-to-string arg)
  439.                    arg)))
  440.          args)))
  441.         
  442.   
  443. (defun custom-message (fmt &rest args)
  444.   "Print a one-line message at the bottom of the screen.
  445. The first argument is a control string.
  446. It may contain %s or %d or %c to print successive following arguments.
  447. %s means print an argument as a string, %d means print as number in decimal,
  448. %c means print a number as a single character.
  449. The argument used by %s must be a string or a symbol;
  450. the argument used by %d or %c must be a number.
  451.  
  452. This is the custom-print replacement for the standard `message'.
  453. See `custom-format' for the details."
  454.   ;; It doesn't work to princ the result of custom-format as in:
  455.   ;; (cust-print-original-princ (apply 'custom-format fmt args))
  456.   ;; because the echo area requires special handling
  457.   ;; to avoid duplicating the output.  
  458.   ;; cust-print-original-message does it right.
  459.   (apply 'cust-print-original-message  fmt
  460.      (mapcar (function (lambda (arg)
  461.                  (if (or (listp arg) (vectorp arg) (symbolp arg))
  462.                  (custom-prin1-to-string arg)
  463.                    arg)))
  464.          args)))
  465.         
  466.  
  467. (defun custom-error (fmt &rest args)
  468.   "Signal an error, making error message by passing all args to `format'.
  469.  
  470. This is the custom-print replacement for the standard `error'.
  471. See `custom-format' for the details."
  472.   (signal 'error (list (apply 'custom-format fmt args))))
  473.  
  474.  
  475.  
  476. ;; Support for custom prin1 and princ
  477. ;;=========================================
  478.  
  479. ;; Defs to quiet byte-compiler.
  480. (defvar circle-table)
  481. (defvar cust-print-current-level)
  482.  
  483. (defun cust-print-original-printer (object))  ; One of the standard printers.
  484. (defun cust-print-low-level-prin (object))    ; Used internally.
  485. (defun cust-print-prin (object))              ; Call this to print recursively.
  486.  
  487. (defun cust-print-top-level (object stream emacs-printer)
  488.   ;; Set up for printing.
  489.   (let ((standard-output (or stream standard-output))
  490.     ;; circle-table will be non-nil if anything is circular.
  491.     (circle-table (and print-circle 
  492.                (cust-print-preprocess-circle-tree object)))
  493.     (cust-print-current-level (or print-level -1)))
  494.  
  495.     (defalias 'cust-print-original-printer emacs-printer)
  496.     (defalias 'cust-print-low-level-prin 
  497.       (cond
  498.        ((or custom-printers
  499.         circle-table
  500.         print-level            ; comment out for version 19
  501.         ;; Emacs doesn't use print-level or print-length
  502.         ;; for vectors, but custom-print can.
  503.         (if custom-print-vectors
  504.         (or print-level print-length)))
  505.     'cust-print-print-object)
  506.        (t 'cust-print-original-printer)))
  507.     (defalias 'cust-print-prin 
  508.       (if circle-table 'cust-print-print-circular 'cust-print-low-level-prin))
  509.  
  510.     (cust-print-prin object)
  511.     object))
  512.  
  513.  
  514. (defun cust-print-print-object (object)
  515.   ;; Test object type and print accordingly.
  516.   ;; Could be called as either cust-print-low-level-prin or cust-print-prin.
  517.   (cond 
  518.    ((null object) (cust-print-original-printer object))
  519.    ((cust-print-use-custom-printer object) object)
  520.    ((consp object) (cust-print-list object))
  521.    ((vectorp object) (cust-print-vector object))
  522.    ;; All other types, just print.
  523.    (t (cust-print-original-printer object))))
  524.  
  525.  
  526. (defun cust-print-print-circular (object)
  527.   ;; Printer for `prin1' and `princ' that handles circular structures.
  528.   ;; If OBJECT appears multiply, and has not yet been printed,
  529.   ;; prefix with label; if it has been printed, use `#N#' instead.
  530.   ;; Otherwise, print normally.
  531.   (let ((tag (assq object circle-table)))
  532.     (if tag
  533.     (let ((id (cdr tag)))
  534.       (if (> id 0)
  535.           (progn
  536.         ;; Already printed, so just print id.
  537.         (cust-print-original-princ "#")
  538.         (cust-print-original-princ id)
  539.         (cust-print-original-princ "#"))
  540.         ;; Not printed yet, so label with id and print object.
  541.         (setcdr tag (- id)) ; mark it as printed
  542.         (cust-print-original-princ "#")
  543.         (cust-print-original-princ (- id))
  544.         (cust-print-original-princ "=")
  545.         (cust-print-low-level-prin object)
  546.         ))
  547.       ;; Not repeated in structure.
  548.       (cust-print-low-level-prin object))))
  549.  
  550.  
  551. ;;================================================
  552. ;; List and vector processing for print functions.
  553.  
  554. (defun cust-print-list (list)
  555.   ;; Print a list using print-length, print-level, and print-circle.
  556.   (if (= cust-print-current-level 0)
  557.       (cust-print-original-princ "#")
  558.     (let ((cust-print-current-level (1- cust-print-current-level)))
  559.       (cust-print-original-princ "(")
  560.       (let ((length (or print-length 0)))
  561.  
  562.     ;; Print the first element always (even if length = 0).
  563.     (cust-print-prin (car list))
  564.     (setq list (cdr list))
  565.     (if list (cust-print-original-princ " "))
  566.     (setq length (1- length))
  567.  
  568.     ;; Print the rest of the elements.
  569.     (while (and list (/= 0 length))
  570.       (if (and (listp list)
  571.            (not (assq list circle-table)))
  572.           (progn
  573.         (cust-print-prin (car list))
  574.         (setq list (cdr list)))
  575.  
  576.         ;; cdr is not a list, or it is in circle-table.
  577.         (cust-print-original-princ ". ")
  578.         (cust-print-prin list)
  579.         (setq list nil))
  580.  
  581.       (setq length (1- length))
  582.       (if list (cust-print-original-princ " ")))
  583.  
  584.     (if (and list (= length 0)) (cust-print-original-princ "..."))
  585.     (cust-print-original-princ ")"))))
  586.   list)
  587.  
  588.  
  589. (defun cust-print-vector (vector)
  590.   ;; Print a vector according to print-length, print-level, and print-circle.
  591.   (if (= cust-print-current-level 0)
  592.       (cust-print-original-princ "#")
  593.     (let ((cust-print-current-level (1- cust-print-current-level))
  594.       (i 0)
  595.       (len (length vector)))
  596.       (cust-print-original-princ "[")
  597.  
  598.       (if print-length
  599.       (setq len (min print-length len)))
  600.       ;; Print the elements
  601.       (while (< i len)
  602.     (cust-print-prin (aref vector i))
  603.     (setq i (1+ i))
  604.     (if (< i (length vector)) (cust-print-original-princ " ")))
  605.  
  606.       (if (< i (length vector)) (cust-print-original-princ "..."))
  607.       (cust-print-original-princ "]")
  608.       ))
  609.   vector)
  610.  
  611.  
  612.  
  613. ;; Circular structure preprocessing
  614. ;;==================================
  615.  
  616. (defun cust-print-preprocess-circle-tree (object)
  617.   ;; Fill up the table.  
  618.   (let (;; Table of tags for each object in an object to be printed.
  619.     ;; A tag is of the form:
  620.     ;; ( <object> <nil-t-or-id-number> )
  621.     ;; The id-number is generated after the entire table has been computed.
  622.     ;; During walk through, the real circle-table lives in the cdr so we
  623.     ;; can use setcdr to add new elements instead of having to setq the
  624.     ;; variable sometimes (poor man's locf).
  625.     (circle-table (list nil)))
  626.     (cust-print-walk-circle-tree object)
  627.  
  628.     ;; Reverse table so it is in the order that the objects will be printed.
  629.     ;; This pass could be avoided if we always added to the end of the
  630.     ;; table with setcdr in walk-circle-tree.
  631.     (setcdr circle-table (nreverse (cdr circle-table)))
  632.  
  633.     ;; Walk through the table, assigning id-numbers to those
  634.     ;; objects which will be printed using #N= syntax.  Delete those
  635.     ;; objects which will be printed only once (to speed up assq later).
  636.     (let ((rest circle-table)
  637.       (id -1))
  638.       (while (cdr rest)
  639.     (let ((tag (car (cdr rest))))
  640.       (cond ((cdr tag)
  641.          (setcdr tag id)
  642.          (setq id (1- id))
  643.          (setq rest (cdr rest)))
  644.         ;; Else delete this object.
  645.         (t (setcdr rest (cdr (cdr rest))))))
  646.     ))
  647.     ;; Drop the car.
  648.     (cdr circle-table)
  649.     ))
  650.  
  651.  
  652.  
  653. (defun cust-print-walk-circle-tree (object)
  654.   (let (read-equivalent-p tag)
  655.     (while object
  656.       (setq read-equivalent-p 
  657.         (or (numberp object) 
  658.         (and (symbolp object)
  659.              ;; Check if it is uninterned.
  660.              (eq object (intern-soft (symbol-name object)))))
  661.         tag (and (not read-equivalent-p)
  662.              (assq object (cdr circle-table))))
  663.       (cond (tag
  664.          ;; Seen this object already, so note that.
  665.          (setcdr tag t))
  666.  
  667.         ((not read-equivalent-p)
  668.          ;; Add a tag for this object.
  669.          (setcdr circle-table
  670.              (cons (list object)
  671.                (cdr circle-table)))))
  672.       (setq object
  673.         (cond 
  674.          (tag ;; No need to descend since we have already.
  675.           nil)
  676.  
  677.          ((consp object)
  678.           ;; Walk the car of the list recursively.
  679.           (cust-print-walk-circle-tree (car object))
  680.           ;; But walk the cdr with the above while loop
  681.           ;; to avoid problems with max-lisp-eval-depth.
  682.           ;; And it should be faster than recursion.
  683.           (cdr object))
  684.  
  685.          ((vectorp object)
  686.           ;; Walk the vector.
  687.           (let ((i (length object))
  688.             (j 0))
  689.         (while (< j i)
  690.           (cust-print-walk-circle-tree (aref object j))
  691.           (setq j (1+ j))))))))))
  692.  
  693.  
  694. ;; Example.
  695. ;;=======================================
  696.  
  697. '(progn
  698.    (progn
  699.      ;; Create some circular structures.
  700.      (setq circ-sym (let ((x (make-symbol "FOO"))) (list x x)))
  701.      (setq circ-list (list 'a 'b (vector 1 2 3 4) 'd 'e 'f))
  702.      (setcar (nthcdr 3 circ-list) circ-list)
  703.      (aset (nth 2 circ-list) 2 circ-list)
  704.      (setq dotted-circ-list (list 'a 'b 'c))
  705.      (setcdr (cdr (cdr dotted-circ-list)) dotted-circ-list)
  706.      (setq circ-vector (vector 1 2 3 4 (list 'a 'b 'c 'd) 6 7))
  707.      (aset circ-vector 5 (make-symbol "-gensym-"))
  708.      (setcar (cdr (aref circ-vector 4)) (aref circ-vector 5))
  709.      nil)
  710.  
  711.    (install-custom-print)
  712.    ;; (setq print-circle t)
  713.  
  714.    (let ((print-circle t))
  715.      (or (equal (prin1-to-string circ-list) "#1=(a b [1 2 #1# 4] #1# e f)")
  716.      (error "circular object with array printing")))
  717.  
  718.    (let ((print-circle t))
  719.      (or (equal (prin1-to-string dotted-circ-list) "#1=(a b c . #1#)")
  720.      (error "circular object with array printing")))
  721.  
  722.    (let* ((print-circle t)
  723.       (x (list 'p 'q))
  724.       (y (list (list 'a 'b) x 'foo x)))
  725.      (setcdr (cdr (cdr (cdr y))) (cdr y))
  726.      (or (equal (prin1-to-string y) "((a b) . #1=(#2=(p q) foo #2# . #1#))"
  727.         )
  728.      (error "circular list example from CL manual")))
  729.  
  730.    (let ((print-circle nil))
  731.      ;; cl-packages.el is required to print uninterned symbols like #:FOO.
  732.      ;; (require 'cl-packages)
  733.      (or (equal (prin1-to-string circ-sym) "(#:FOO #:FOO)")
  734.      (error "uninterned symbols in list")))
  735.    (let ((print-circle t))
  736.      (or (equal (prin1-to-string circ-sym) "(#1=FOO #1#)")
  737.      (error "circular uninterned symbols in list")))
  738.  
  739.    (uninstall-custom-print)
  740.    )
  741.  
  742. (provide 'cust-print)
  743.  
  744. ;;; cust-print.el ends here
  745.  
  746.